home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #2 / Monster Media No. 2 (Monster Media)(1994).ISO / utils1 / 2m21src.zip / 2MF.C < prev    next >
C/C++ Source or Header  |  1994-05-31  |  33KB  |  939 lines

  1.  
  2. /*───────────────────────────────────────────────────────────────────\
  3. │                                                                    │
  4. │                         █████ █   █ █▀▀▀▀                          │
  5. │                             █ ██ ██ █                              │
  6. │                         █████ █ █ █ █▀▀                            │
  7. │                         █     █   █ █                              │
  8. │                         █████ █   █ █                              │
  9. │                                                                    │
  10. │        2MF.C  2.1  -  UTILIDAD DE FORMATEO DE DISQUETES 2M         │
  11. │                                                                    │
  12. │                  (c) 1994 Ciriaco García de Celis.                 │
  13. │                                                                    │
  14. │   - Para Borland C++ 2.0 ó superior en modelo de memoria LARGE.    │
  15. │   - Este programa se compila abriendo un proyecto e introduciendo  │
  16. │     en él 2MF.C, 2MFKIT.OBJ, 2MFBOTHD.OBJ y 2MFBOTDD.OBJ           │
  17. │                                                                    │
  18. │   - NOTA: Las funciones de bajo nivel que acceden directamente a   │
  19. │           la controladora de disquetes no son indispensables, tan  │
  20. │           sólo se emplean para producir menos ruido al detectar    │
  21. │           la introducción de un nuevo disquete en la unidad.       │
  22. │                                                                    │
  23. \───────────────────────────────────────────────────────────────────*/
  24.  
  25.  
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <dos.h>
  30. #include <bios.h>
  31. #include <time.h>
  32. #include <alloc.h>
  33.  
  34. unsigned _stklen=16384;
  35.  
  36. #define MAXSECT      46   /* máximo número de sectores por pista */
  37. #define MAXFAT     6128   /* mayor FAT de 12 bits posible */
  38. #define FD_DATA   0x3F5   /* registro de datos del 765 */
  39. #define FD_STATUS 0x3F4   /* registro principal de estado del 765 */
  40. #define FD_DOR    0x3F2   /* registro de salida digital */
  41. #define FD_DIR    0x3F7      /* registro de entrada digital (RD) */
  42. #define FD_DCR    0x3F7      /* registro de control del disquete (WR) */
  43.  
  44.  
  45. struct boot {                       /* sector arranque disquetes 2M */
  46.   unsigned char Salto[3], IdSis[8];
  47.   short    BytesSect;
  48.   char     SectCluster;
  49.   short    SectReserv;
  50.   char     NumFats;
  51.   short    FichRaiz, NumSect;
  52.   char     MediaId;
  53.   short    SectFat, SectPista, Caras;
  54.   long     Especiales, Sect32;
  55.   char     Unidad, Reservado, Flag;
  56.   long     NumSerie;
  57.   char     Titulo[11], TipoFat[8];
  58.   char     NoUsado;
  59.   char     CheckSum;
  60.   char     VersionFmt, FlagWr, VelPista0, VelPistaX;
  61.   short    OffsetJmp, OffsetPista0, OffsetPistaX, OffsetListaTam;
  62.   char     Resto[512-76];
  63.   };
  64.  
  65. struct parametros {              /* parámetros en línea de comandos */
  66.   int   Unidad, HD, ED, TipoFmt, NoVerify, MarcaPoco,
  67.         Pistas, FichRaiz, Silencioso, NoPausa, X, Y, G;
  68.   };
  69.  
  70.  
  71. int    HablaSp(), Hay2m(), Hay2mBoot(), FormatearDisco(), MarcaFat(),
  72.        TipoDrive(), InicializaDisco(), EsperarCambioDisco(), infdc();
  73. void   Ayuda(), ProcesarParametros(), CrearSector0(),
  74.        DiagnosticoError(), InformeError(), InformeDisco(),
  75.        SonidoSube(), SonidoBaja(), SonidoError(), SonidoOn(),
  76.        SonidoOff(), Sonido(), posicionar(), outfdc(), EsperarInt();
  77. extern BootHDPrg, BootHDPrgLong, BootDDPrg, BootDDPrgLong,
  78.        Boot2mCode, Boot2mLong, biosdsk();
  79. extern void PicoRetardo();
  80.  
  81.  
  82. int      sp;                  /* 1-español 0-inglés */
  83. unsigned char far *fat;       /* para contener toda la FAT */
  84. unsigned char far *buffer;    /* para contener toda una pista */
  85.  
  86. unsigned long far *cbios=MK_FP(0x40, 0x6C);  /* reloj del sistema */
  87. unsigned char far *irq6=MK_FP(0x40, 0x3E);   /* flag BIOS de IRQ6 */
  88.  
  89.  
  90. void main (int argc, char **argv)
  91. {
  92.   struct boot sector0;
  93.   struct parametros cmd;
  94.   int    salir, result, sg;
  95.   long   bytes_err, dir;
  96.  
  97.   sp=HablaSp();  /* determinar idioma del país */
  98.  
  99.   ProcesarParametros (argc, argv, &cmd);
  100.  
  101.   if (!Hay2m())
  102.       if (!Hay2mBoot()) {
  103.         if (sp)
  104.             printf("  2M ó 2MX 2.1 no está instalado, imposible formatear.\n");
  105.           else
  106.             printf("  2M or 2MX 2.1 is not installed, impossible to format.\n");
  107.         exit(128);
  108.         }
  109.       else {
  110.         if (sp)
  111.             printf("  Modo SuperBOOT: instale 2M para dar formato.\n");
  112.           else
  113.             printf("  SuperBOOT mode: needed to install 2M to format.\n");
  114.         exit(127);
  115.         }
  116.  
  117.   if (((fat=farmalloc( (unsigned long) MAXFAT))==NULL) ||
  118.       ((buffer=farmalloc( (unsigned long) MAXSECT<<10))==NULL)) {
  119.       if (sp) printf("  Memoria insuficiente.\n");
  120.         else printf("  Insufficient memory.\n");
  121.       exit(126);
  122.       }
  123.  
  124.   /* Definir el buffer para que no cruce una frontera de DMA */
  125.  
  126.   dir = ((unsigned long) FP_SEG(buffer) <<4) + FP_OFF(buffer);
  127.   if ((dir >> 16) != ((dir + ((unsigned long) MAXSECT << 9)) >> 16))
  128.     buffer+=(unsigned long) MAXSECT << 9;
  129.  
  130.   if (!cmd.NoPausa) {
  131.       if (sp)
  132.           printf("  Pulsa una tecla para formatear en");
  133.         else
  134.           printf("  Press any key to format on");
  135.       printf(" %c:", cmd.Unidad+'A');
  136.       salir=getch()==27;
  137.       }
  138.     else
  139.       salir=0;
  140.  
  141.   while (!salir) {
  142.     CrearSector0 (§or0, cmd);
  143.     if (!cmd.Silencioso) SonidoSube();
  144.     switch (result=FormatearDisco (§or0, &cmd, &bytes_err, &sg)) {
  145.       case 0:  InformeDisco (§or0, bytes_err, sg);
  146.                if (!cmd.Silencioso) SonidoBaja(); break;
  147.       case 1:  DiagnosticoError (result);
  148.                break;
  149.       default: DiagnosticoError (result);
  150.                if (!cmd.Silencioso) SonidoError(); break;
  151.       }
  152.     if (sp)
  153.         printf("\n  Introduce otro disquete para formatear en");
  154.       else
  155.         printf("\n  Please insert another disk to format in");
  156.     printf(" %c:", cmd.Unidad+'A');
  157.  
  158.     if (!EsperarCambioDisco(cmd.Unidad)) salir=1;
  159.     }
  160.   printf("\r                                                     \r");
  161. }
  162.  
  163.  
  164. void ProcesarParametros(int argc, char **argv, struct parametros *cmd)
  165. {
  166.   int pm, error=0, hlp=0, id=1;
  167.  
  168.   cmd->Unidad=cmd->TipoFmt=cmd->ED=cmd->NoVerify=cmd->MarcaPoco=0;
  169.   cmd->HD=1; cmd->Pistas=82;
  170.   cmd->FichRaiz=cmd->Silencioso=cmd->NoPausa=0;
  171.   cmd->X=cmd->Y=cmd->G=-1;
  172.   for (pm=1; pm<argc; pm++) {
  173.     strupr (argv[pm]);
  174.     if (strstr(argv[pm],"/?")!=NULL) hlp++;
  175.     else if (strstr(argv[pm],"/H")!=NULL) hlp++;
  176.     else if ((strstr(argv[pm],"A:")!=NULL) ||
  177.       (strstr(argv[pm],"B:")!=NULL)) cmd->Unidad=*argv[pm]-'A';
  178.     else if (strstr(argv[pm],"/DD")!=NULL) cmd->HD=0;
  179.     else if (strstr(argv[pm],"/D0")!=NULL) cmd->HD=2;
  180.     else if (strstr(argv[pm],"/D1")!=NULL) cmd->HD=3;
  181.     else if (strstr(argv[pm],"/F")!=NULL) cmd->TipoFmt=0;
  182.     else if (strstr(argv[pm],"/M")!=NULL) cmd->TipoFmt=1;
  183.     else if (strstr(argv[pm],"/E")!=NULL) cmd->ED=1;
  184.     else if (strstr(argv[pm],"/N")!=NULL) cmd->NoVerify=1;
  185.     else if (strstr(argv[pm],"/W")!=NULL) cmd->MarcaPoco=1;
  186.     else if (strstr(argv[pm],"/T")!=NULL)
  187.       cmd->Pistas = atoi (&argv[pm][3]);
  188.     else if (strstr(argv[pm],"/R")!=NULL)
  189.       cmd->FichRaiz = atoi (&argv[pm][3]);
  190.     else if (strstr(argv[pm],"/S")!=NULL) { cmd->Silencioso=1; id++; }
  191.     else if (strstr(argv[pm],"/K")!=NULL) cmd->NoPausa=1;
  192.     else if (strstr(argv[pm],"/X")!=NULL) cmd->X=atoi(&argv[pm][3]);
  193.     else if (strstr(argv[pm],"/Y")!=NULL) cmd->Y=atoi(&argv[pm][3]);
  194.     else if (strstr(argv[pm],"/G")!=NULL) cmd->G=atoi(&argv[pm][3]);
  195.     else if (strstr(argv[pm],"/I")!=NULL) { sp^=1; id++; }
  196.     else error=1;
  197.     }
  198.  
  199.   if (cmd->ED && (cmd->HD!=1)) cmd->HD=1;  /* /DD ó /Dx + /E = /E */
  200.  
  201.   if ((argc<=1) || (argc==id)) hlp++;
  202.  
  203.   if (hlp) Ayuda();
  204.  
  205.   if (sp)
  206.       printf("\n2MF 2.1 - Utilidad de formateo de disquetes 2M         (ESC Salir)\n");
  207.     else
  208.       printf("\n2MF 2.1 - Format utility program for 2M diskettes      (ESC Aborts)\n");
  209.   if (error) {
  210.     if (sp)
  211.         printf("  Error de sintaxis. Ejecute 2MF /?.\n");
  212.       else
  213.         printf("  Incorrect parameter(s). Execute 2MF /?.\n");
  214.     exit (2);
  215.     }
  216.   if (TipoDrive(cmd->Unidad)==0) {
  217.     if (sp)
  218.         printf("    La unidad física indicada no existe.\n");
  219.       else
  220.         printf("    Physical drive indicated does not exist.\n");
  221.     exit (2);
  222.     }
  223.   if ((TipoDrive(cmd->Unidad)!=2) && (TipoDrive(cmd->Unidad)<4)) {
  224.     if (sp)
  225.         printf("    La unidad indicada no es de alta densidad.\n");
  226.       else
  227.         printf("    Drive indicated it is not high density one.\n");
  228.     exit (2);
  229.     }
  230.   if ((TipoDrive(cmd->Unidad)<5) && (cmd->ED==1)) {
  231.     if (sp)
  232.         printf("    Necesaria unidad de 2.88M para formato ED.\n");
  233.       else
  234.         printf("    Needs a 2.88M drive to perform ED format.\n");
  235.     exit (2);
  236.     }
  237.   if ((cmd->Pistas<80) || (cmd->Pistas>86)) {
  238.     if (sp)
  239.         printf("  Error: Número de pistas incorrecto.\n");
  240.       else
  241.         printf("  Error: Incorrect number of tracks.\n");
  242.     exit (2);
  243.     }
  244.   if (cmd->FichRaiz && ((cmd->FichRaiz<1) || (cmd->FichRaiz>240))) {
  245.     if (sp)
  246.         printf("  Error: Nº de ficheros en directorio raiz erróneo.\n");
  247.       else
  248.         printf("  Error: Bad number of files in root directory.\n");
  249.     exit (2);
  250.     }
  251. }
  252.  
  253.  
  254. void Ayuda(void)
  255. {
  256.   if (sp) {
  257.       printf("\n\n"
  258.         "          2MF 2.1 - UTILIDAD ESTANDAR DE FORMATEO DE DISQUETES PARA 2M\n"
  259.         "      (c) 1994  Ciriaco García de Celis - Grupo Universitario de Informática\n"
  260.         "    C/Renedo, 2, 4-C; 47005 Valladolid (España) - ciri@gui.uva.es - 2:341/21.8\n\n"
  261.         "             2MF U: [/DD] [/F|M] [/E] [/N] [/T=nn] [/R=nn] [/S] [/K]\n\n"
  262.         "    Este programa formatea disquetes a una mayor capacidad y/o velocidad de la\n"
  263.         "  normal. Para que estos nuevos disquetes funcionen debe estar instalado 2M en\n"
  264.         "  memoria. Alternativamente, si son de alta densidad se pueden dejar dentro de\n"
  265.         "  la unidad A: y reinicializar el ordenador,  que botará pese a todo del disco\n"
  266.         "  duro y podrá acceder a los disquetes 2M sin problemas en lectura y escritura\n"
  267.         "  normales. Este programa es gratuíto y de tipo «CARDWARE». Opciones:\n\n"
  268.         "  /DD  Solicita un formateo en doble densidad -por defecto se hace en alta-.\n"
  269.         "   /F  Disquetes rápidos y seguros -por defecto- (5¼:820-1476K, 3½:984-1804K).\n"
  270.         "   /M  Formatear disquetes a la máxima capacidad (5¼:902-1558K, 3½:1066-1886K).\n"
  271.         "   /E  Formatear disquetes de 3½-ED (3608K por defecto o 3772K indicando /M).\n"
  272.         "   /N  No verificar el disquete destino (peligroso en modo /M).\n\n"
  273.         "   /T  Modificar el número de pistas por defecto (80-86).\n"
  274.         "   /R  Modificar el número de ficheros permitidos en directorio raíz (1-240).\n"
  275.         "   /S  Funcionamiento silencioso sin emitir sonido.\n"
  276.         "   /K  No realizar pausa inicial antes de comenzar.\n");
  277.       }
  278.     else {
  279.       printf("\n\n"
  280.         "               2MF 2.1 - STANDARD FORMAT UTILITY FOR 2M DISKETTES\n"
  281.         "      (c) 1994 Ciriaco García de Celis - Grupo Universitario de Informática\n"
  282.         "    C/Renedo, 2, 4-C; 47005 Valladolid (Spain) - ciri@gui.uva.es - 2:341/21.8\n\n"
  283.         "             2MF U: [/DD] [/F|M] [/E] [/N] [/T=nn] [/R=nn] [/S] [/K]\n\n"
  284.         "    This program formats diskettes at a higher capacity and/or speed than the\n"
  285.         "  normal ones.  2M must be installed on memory to provide support for the new\n"
  286.         "  diskettes.  Also, high-density diskettes can be left into A: drive and then\n"
  287.         "  computer can be rebooted: really it will boot from hard disk and after this\n"
  288.         "  moment 2M diskettes will be supported in the standard read-write operation.\n"
  289.         "  2MF is a 100%% CARDWARE utility. Meaning of switches:\n\n"
  290.         "  /DD  Request a double-density format (by default it will be high-density).\n"
  291.         "   /F  Fast and secure diskettes  -by default-  (5¼:820-1476K, 3½:984-1804K).\n"
  292.         "   /M  Formats diskettes up to maximum capacity (5¼:902-1558K, 3½:1066-1886K).\n"
  293.         "   /E  Formats 3.5-ED diskettes at 3608K (or 3772K if /M option enabled).\n"
  294.         "   /N  Do not verify target diskette (dangerous in /M mode).\n\n"
  295.         "   /T  Sets the number of tracks to be used (80-86).\n"
  296.         "   /R  Sets the number of root directory entries (1-240).\n"
  297.         "   /S  Tells 2MF not to make sound effects.\n"
  298.         "   /K  No initial pause before formatting.\n");
  299.       }
  300.   exit (1);
  301. }
  302.  
  303.  
  304. int Hay2m()     /* devolver 1 si 2M está instalado */
  305. {
  306.   int entrada, instalado=0;
  307.   union REGS r; struct SREGS s;
  308.  
  309.   for (entrada=0xc0; (entrada<=0xff) && (!instalado); entrada++) {
  310.     r.x.ax=entrada << 8; s.es=0x1492; r.x.di=0x1992;
  311.     int86x (0x2f, &r, &r, &s);
  312.     if (r.x.ax==0xFFFF)
  313.       if ((peek(s.es,r.x.di-4)==9002) && (peek(s.es,r.x.di-2)==10787))
  314.         if (strstr (MK_FP(s.es, r.x.di),"2M:2.1")) instalado=1;
  315.         if (strstr (MK_FP(s.es, r.x.di),"2MX:2.1")) instalado=1;
  316.     }
  317.   return (instalado);
  318. }
  319.  
  320.  
  321. int Hay2mBoot()     /* devolver 1 si 2M instalado en modo SuperBOOT */
  322. {
  323.   return (strstr(MK_FP(((unsigned) peek(0x40, 0x13) * 64), 4),
  324.                  "2M-STV")!=NULL);
  325. }
  326.  
  327.  
  328. void CrearSector0 (struct boot *s0, struct parametros cmd)
  329. {
  330.   unsigned  tipo, tabla, i, j, k, m, t, s, tam, ini, fin, inc;
  331.   char id[8]="2M-STV00", ch, sum, far *p;
  332.   static unsigned char infofis [2][3][2][4][20] =
  333.   {{{{{10,176,7,0,1,1},        {9,80,1,1},            /* 5¼-DD  /F */
  334.       {5,100,3,1,1}                             },
  335.      {{11,176,7,1,1,1},        {9,80,1,1},            /*        /M */
  336.       {32,4,5,3,1,4,2,0},      {4,2,4,3,0}      }},
  337.     {{{18,224,7,0,0,0},        {16,60,1,1},           /* 5¼-HD  /F */
  338.       {9,50,3,1,2}                              },
  339.      {{19,224,7,1,0,0},        {17,25,1,2},           /*        /M */
  340.       {53,3,6,4,1,5,2,6,3},    {4,4,2,4,4,3}    }},
  341.     {{{0,0,0,0,0,0},           {0,0,0,0},             /* no usado  */
  342.       {0,0,0,0,0},                              },
  343.      {{14,192,7,1,2,1},        {9,80,1,1},            /* 3½-DD /D1 */
  344.       {38,2,4,3,1,4,2},        {4,3,4,4}        }}},
  345.    {{{{12,192,7,0,2,1},        {9,80,1,1},            /* 3½-DD  /F */
  346.       {6,100,3,1,1}                             },
  347.      {{13,192,7,1,2,1},        {9,80,1,1},            /*        /M */
  348.       {38,5,6,3,1,4,2,0,0},    {4,2,4,4,0,0}    }},
  349.     {{{22,224,7,0,0,0},        {19,70,1,1},           /* 3½-HD  /F */
  350.       {11,40,3,1,2}                             },
  351.      {{23,224,7,1,0,0},        {19,70,1,1},           /*        /M */
  352.       {64,3,7,4,1,5,2,6,3,7},  {4,4,4,4,4,3,2}  }},
  353.     {{{44,240,7,0,3,3},        {36,108,1,1},          /* 3½-ED  /F */
  354.       {11,126,4,1,2}                            },
  355.      {{46,240,7,1,3,3},        {36,108,1,1},          /*        /M */
  356.       {127,5,12,1,7,2,8,3,9,4,10,5,11,6,12},
  357.       {4,4,4,4,4,4,4,4,4,4,4,3}                 }}}};
  358.  
  359.   /* Significado de la tabla /F:
  360.       {SectLogPistaX, fichraiz, verFmt, flagWr, velpista0, velpistaX},
  361.       {sectpista0, GAP3pista0, primsectpista0, interleavepista0},
  362.       {SectFisPistaX, GAP3pistaX, tamsectpistaX, /X, /Y}
  363.      Significado de la tabla /M:
  364.       {SectLogPistaX, fichraiz, verFmt, flagWr, velpista0, velpistaX},
  365.       {sectpista0, GAP3pista0, primsectpista0, interleavepista0},
  366.       {Sectpreformat, GAP3pistaX, SectFisPistaX, sects numerados...},
  367.       {tamaños de sectores por orden...}
  368.   */
  369.  
  370.   if ((cmd.HD==2) && (TipoDrive(cmd.Unidad)>=4)) {
  371.       cmd.HD=0; tabla=0; tipo=0;
  372.       infofis[0][0][cmd.TipoFmt][0][4]=2;    /* 3½-DD a 250 Kbps */
  373.       infofis[0][0][cmd.TipoFmt][0][5]=2;
  374.       }
  375.   else if ((cmd.HD==3) && (TipoDrive(cmd.Unidad)>=4)) {
  376.       cmd.HD=tipo=0;
  377.       cmd.TipoFmt=1; tabla=2;                /* 3½-DD con 1148K */
  378.       }
  379.     else {
  380.       if (cmd.HD>1) cmd.HD=0;
  381.       tabla=cmd.HD+cmd.ED;            /* seleccionar tabla de datos */
  382.       if (TipoDrive(cmd.Unidad)<3)
  383.           tipo=0;  /* 5¼ */
  384.         else
  385.           tipo=1;  /* 3½ */
  386.       }
  387.  
  388.   s0->NoUsado=0;
  389.  
  390.   ch=1+cmd.HD;
  391.   if (TipoDrive(cmd.Unidad)>2) ch+=2; if (!cmd.TipoFmt) ch+=4;
  392.   if (cmd.ED) ch=10-cmd.TipoFmt;
  393.   id[6]=(ch/10)+'0'; id[7]=(ch % 10)+'0'; strncpy (s0->IdSis, id, 8);
  394.  
  395.   s0->BytesSect=512;
  396.   s0->SectCluster = s0->SectReserv = 1;  s0->NumFats=2;
  397.   if (cmd.ED) s0->SectCluster=2;
  398.  
  399.   if (!cmd.FichRaiz)
  400.       s0->FichRaiz=infofis[tipo][tabla][cmd.TipoFmt][0][1];
  401.     else
  402.       if (cmd.FichRaiz % 16)
  403.           s0->FichRaiz=((cmd.FichRaiz >> 4) + 1) << 4;
  404.         else
  405.           s0->FichRaiz=cmd.FichRaiz;
  406.  
  407.   if (ch==6)
  408.       s0->MediaId=0xF0;   /* compatible SCANDISK */
  409.     else
  410.       s0->MediaId=0xFA;   /* compatible SCANDISK */
  411.  
  412.   s0->SectPista=infofis[tipo][tabla][cmd.TipoFmt][0][0];
  413.   s0->Caras=2;
  414.   s0->NumSect=cmd.Pistas*s0->Caras*s0->SectPista;
  415.  
  416.   j = 3 * (s0->NumSect - (s0->FichRaiz>>4) - 1);
  417.   k = 6 + 1024 * s0->SectCluster;
  418.   s0->SectFat = j/k; if (j % k) s0->SectFat++;
  419.  
  420.   s0->Unidad = s0->Reservado = 0; s0->Especiales = s0->Sect32 = 0L;
  421.   s0->Flag=0x29; randomize();
  422.   for (i=0; i<4; i++)
  423.     s0->NumSerie = (s0->NumSerie<<8) | (unsigned char) random(32767);
  424.  
  425.   strncpy (s0->Titulo, "NO NAME    ", 11);
  426.   strncpy (s0->TipoFat, "FAT12   ", 8);
  427.  
  428.   s0->VersionFmt=infofis[tipo][tabla][cmd.TipoFmt][0][2];
  429.   s0->FlagWr=infofis[tipo][tabla][cmd.TipoFmt][0][3];
  430.   s0->VelPista0=infofis[tipo][tabla][cmd.TipoFmt][0][4];
  431.   s0->VelPistaX=infofis[tipo][tabla][cmd.TipoFmt][0][5];
  432.  
  433.   tam=76; /* lo que precede a la primera tabla */
  434.   s0->OffsetPista0=tam;
  435.   s0->Resto[0]=infofis[tipo][tabla][cmd.TipoFmt][1][0];
  436.   s0->Resto[1]=infofis[tipo][tabla][cmd.TipoFmt][1][1];
  437.   ch=infofis[tipo][tabla][cmd.TipoFmt][1][2];
  438.   inc=infofis[tipo][tabla][cmd.TipoFmt][1][3];
  439.   ini=tam+2; fin=ini+s0->Resto[0]; k=0;
  440.   for (i=j=0; j<s0->Resto[0]; j++) {
  441.     s0->Salto[ini+i]=ch++; if (ch>s0->Resto[0]) ch=1;
  442.     i+=inc; if (ini+i>=fin) i=++k;
  443.     }
  444.  
  445.   ini=fin; s0->OffsetPistaX=ini;
  446.   if (!s0->FlagWr) {
  447.       k=infofis[tipo][tabla][cmd.TipoFmt][2][0]; j=5;
  448.       for (i=0; i<j; i++)
  449.         s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][2][i];
  450.       if (cmd.X!=-1) s0->Salto[ini+3]=cmd.X;
  451.       if (cmd.Y!=-1) s0->Salto[ini+4]=cmd.Y;
  452.       }
  453.     else {
  454.       k=infofis[tipo][tabla][cmd.TipoFmt][2][2]; j=(k+1)*3;
  455.       for (i=0; i<3; i++)
  456.         s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][2][i];
  457.       m=129;
  458.       for (i=3; i<=k*3; i+=3) {
  459.         s0->Salto[ini+i]=m;
  460.         s=infofis[tipo][tabla][cmd.TipoFmt][2][i/3+2];
  461.         s0->Salto[ini+i+1]=s;
  462.         t=infofis[tipo][tabla][cmd.TipoFmt][3][s-1];
  463.         switch (t) {
  464.           case 0: m+=1;  break;   case 1: m+=2;  break;
  465.           case 2: m+=3;  break;   case 3: m+=6;  break;
  466.           case 4: m+=11; break;   case 5: m+=22; break;
  467.           }
  468.         s0->Salto[ini+i+2]=t;
  469.         }
  470.       }
  471.   if (cmd.G!=-1) s0->Salto[ini+1]=cmd.G;
  472.   fin=ini+j;
  473.  
  474.   ini=fin; s0->OffsetListaTam=ini;
  475.   if (!s0->FlagWr)
  476.       for (i=0; i<k; i++)
  477.         s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][2][2];
  478.     else
  479.       for (i=0; i<k; i++)
  480.         s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][3][i];
  481.   fin=ini+k;
  482.  
  483.   ini=fin; s0->OffsetJmp=ini;
  484.   s0->Salto[0]=0xE9;
  485.   s0->Salto[1]=(ini-3) % 256; s0->Salto[2]=(ini-3) >> 8;
  486.  
  487.   if (cmd.HD == 0) {
  488.       p=(char far *) &BootDDPrg; k=BootDDPrgLong; }
  489.     else {
  490.       p=(char far *) &BootHDPrg; k=BootHDPrgLong; }
  491.  
  492.   for (i=0; (i<k) && (ini+i<509); i++) s0->Salto[ini+i]=*p++;
  493.   fin=ini+i;
  494.  
  495.   for (i=fin; i<510; i++) s0->Salto[i]=0;
  496.   if (fin<497) strncpy (&s0->Salto[496], "Made in Spain", 13);
  497.   s0->Salto[509]=0; s0->Salto[510]=0x55; s0->Salto[511]=0xAA;
  498.  
  499.   for (sum=0, j=64; j<ini; j++) sum+=s0->Salto[j]; /* checksum */
  500.   s0->CheckSum=-sum;
  501. }
  502.  
  503.  
  504. int FormatearDisco (sector0, cmd, bytes_defectuosos, segundos)
  505. struct boot *sector0;
  506. struct parametros *cmd;
  507. long *bytes_defectuosos;
  508. int *segundos;
  509. {
  510.   unsigned long dir, tiempo, rest, tini, hist[86], i;
  511.   int      cilindros, cilindro, cabezal, intento, error=1, spista, t;
  512.   unsigned long fase, fases;
  513.  
  514.   if (cmd->G!=-1)
  515.     if (sp)
  516.         printf("\r  AVISO: ¡Valor de GAP alterado con opción /G!\n");
  517.       else
  518.         printf("\r  WARNING: GAP value modified with /G switch!\n");
  519.  
  520.   if (cmd->HD>1)
  521.     if (sp)
  522.         printf("\r  AVISO: ¡Parámetro indocumentado /D%d activo!\n",
  523.                cmd->HD-2);
  524.       else
  525.         printf("\r  WARNING: Undocumented /D%d switch activated!\n",
  526.                cmd->HD-2);
  527.  
  528.   if (cmd->MarcaPoco)
  529.     if (sp)
  530.         printf("\r  AVISO: ¡Parámetro indocumentado /W activo!\n");
  531.       else
  532.         printf("\r  WARNING: Undocumented /W switch activated!\n");
  533.  
  534.   if ((cmd->X!=-1) || (cmd->Y!=-1))
  535.     if (sp)
  536.         printf("\r  AVISO: ¡Parámetro indocumentado /X ó /Y activo!\n");
  537.       else
  538.         printf("\r  WARNING: Undocumented /X or /Y switch activated!\n");
  539.  
  540.   if (sp)
  541.       printf("\r  Formateo de disquete ");
  542.     else
  543.       printf("\r  Formatting ");
  544.  
  545.   switch (TipoDrive (cmd->Unidad)) {
  546.     case 2:  printf("%s", cmd->HD==1?"5¼-1.2M":"5¼-360K");  break;
  547.     case 4:  printf("%s", cmd->HD==1?"3½-1.44M":"3½-720K"); break;
  548.     default: if (cmd->ED) printf("3½-2.88M");
  549.                else printf("%s", cmd->HD==1?"3½-1.44M":"3½-720K");
  550.     }
  551.  
  552.   if (sp)
  553.       printf(" en %c: con %dK        \n",
  554.              cmd->Unidad+'A', sector0->NumSect>>1);
  555.     else
  556.       printf(" diskette on %c: with %dK        \n",
  557.              cmd->Unidad+'A', sector0->NumSect>>1);
  558.  
  559.   for (i=0; i<MAXFAT; i++) fat[i]=0;  /* poner a 0 la futura FAT */
  560.   fat[0]=sector0->MediaId; fat[1]=fat[2]=0xFF;
  561.  
  562.   for (i=0; i < ((unsigned long) MAXSECT <<9); i++) buffer[i]=0;
  563.  
  564.   cilindros=sector0->NumSect/(sector0->SectPista*sector0->Caras);
  565.   spista=sector0->SectPista; *bytes_defectuosos=0L;
  566.   fases=1L*cilindros*sector0->Caras*(1+(1-cmd->NoVerify)+sector0->FlagWr);
  567.   fase=0L;
  568.  
  569.   tini=*cbios;
  570.   for (cilindro=0; cilindro < cilindros; cilindro++) {
  571.     for (cabezal=0; cabezal<sector0->Caras; cabezal++) {
  572.       for (intento=0; intento<3; intento++) {
  573.         if (sp)
  574.             printf("\r  Cilindro %2d - Cara %d  [F-]  %3lu%%",
  575.                    cilindro, cabezal, fase*100/fases);
  576.           else
  577.             printf("\r  Cylinder %2d - Side %d  [F-]  %3lu%%",
  578.                    cilindro, cabezal, fase*100/fases);
  579.         if (error) biosdsk (0, cmd->Unidad);
  580.         t=0; while (bioskey(1)) t=bioskey(0);
  581.         if ((t & 0xFF)==0x1B) { error=1; goto AbortFormat; }
  582.           else if ((t==0x1000) && (cilindro>1)) goto FinFormat;
  583.         error=biosdsk (5, cmd->Unidad, cabezal,
  584.                        cilindro, 0, 0x7F, sector0);
  585.         if (sector0->FlagWr==1) if (!error && (cilindro | cabezal)) {
  586.           printf ("\b\b\b\b\b\b\b\b\bI-]  %3lu%%",(fase+1)*100/fases);
  587.           error=biosdsk (3, cmd->Unidad, cabezal | 0x80,
  588.                          cilindro, 1, spista, buffer);
  589.           }
  590.         if (!error&&(!cmd->NoVerify||(cmd->NoVerify && cilindro<2))) {
  591.           printf ("\b\b\b\b\b\b\b\b\b-V]  %3lu%%",
  592.                  (fase+1+sector0->FlagWr)*100/fases);
  593.           error=biosdsk (2, cmd->Unidad, cabezal,
  594.                          cilindro, 1, spista, buffer);
  595.           }
  596.         if (!error) break;
  597.         }
  598.       if (error)
  599.         if ((error==128) || (error==3) || (error==6))
  600.             goto AbortFormat;   /* error fatal */
  601.           else
  602.             if (!MarcaFat(cmd->Unidad, cmd->MarcaPoco, sector0,
  603.                 cilindro, cabezal, fat, bytes_defectuosos))
  604.               goto AbortFormat; /* error en áreas del sistema */
  605.       fase+=(1+(1-cmd->NoVerify)+sector0->FlagWr);
  606.     }
  607.     hist[cilindro]=*cbios;
  608.     tiempo=(*cbios-tini)*10/182;
  609.     printf("                [%2lu:%02lu ]", tiempo/60, tiempo % 60);
  610.     if (cilindro>5) {
  611.       rest=(*cbios-hist[cilindro-5])*(cilindros-cilindro)*10/910;
  612.       printf("\b+%2lu:%02lu =%2lu:%02lu ]", rest/60, rest % 60,
  613.              (tiempo+rest)/60, (tiempo+rest) % 60);
  614.       }
  615.   }
  616.  
  617.   FinFormat: error=InicializaDisco (cmd->Unidad, sector0, fat);
  618.  
  619.   AbortFormat: printf("\r"); for (i=0; i<79; i++) printf(" ");
  620.  
  621.   *segundos=(*cbios-tini)*10/182;
  622.  
  623.   return (error);
  624. }
  625.  
  626.  
  627. void InformeDisco (struct boot *s0, long bd, int tiempo)
  628. {
  629.   unsigned long st, ua, bt;
  630.  
  631.   st = s0->NumSect - s0->NumFats * s0->SectFat
  632.        - s0->SectReserv - (s0->FichRaiz>>4);
  633.   ua = st / (unsigned long) s0->SectCluster;  bt = st*512L;
  634.  
  635.   if (sp) {
  636.       printf ("\r  Tiempo transcurrido formateando %2d:%02d\n",
  637.         tiempo/60, tiempo % 60);
  638.       printf ("  Volúmen con número de serie %04X-%04X\n",
  639.         (int) (s0->NumSerie >> 16), (int) s0->NumSerie);
  640.       printf ("%9d ficheros permitidos en el raíz.\n",
  641.         s0->FichRaiz);
  642.       printf ("%9d unidades de asignación.\n", ua);
  643.       printf ("%9d bytes por unidad de asignación.\n",
  644.         s0->SectCluster*512);
  645.       printf ("%9lu bytes totales en el disco.\n", bt);
  646.       printf ("%9lu bytes en sectores defectuosos.\n", bd);
  647.       printf ("%9lu bytes disponibles en el disco.\n", bt-bd);
  648.       }
  649.     else {
  650.       printf ("\r  Time elapsed in the process %2d:%02d\n",
  651.         tiempo/60, tiempo % 60);
  652.       printf ("  Volume serial number is %04X-%04X\n",
  653.         (int) (s0->NumSerie >> 16), (int) s0->NumSerie);
  654.       printf ("%9d file capacity of root directory.\n",
  655.         s0->FichRaiz);
  656.       printf ("%9d total clusters on disk.\n", ua);
  657.       printf ("%9d bytes per cluster.\n",
  658.         s0->SectCluster*512);
  659.       printf ("%9lu total bytes on disk.\n", bt);
  660.       printf ("%9lu bytes on bad sectors.\n", bd);
  661.       printf ("%9lu bytes available on disk.\n", bt-bd);
  662.       }
  663. }
  664.  
  665.  
  666. void DiagnosticoError (int codigo)
  667. {
  668.   if (sp) {
  669.       switch (codigo) {
  670.         case 1:   printf("\r  Formateo interrumpido por el usuario.");
  671.                   break;
  672.         case 2:   printf("\r  La densidad seleccionada es incorrecta.");
  673.                   break;
  674.         case 3:   printf("\r  Disquete protegido contra escritura.");
  675.                   break;
  676.         case 6:
  677.         case 128: printf("\r  Unidad no preparada (¿puerta abierta?).");
  678.                   break;
  679.         default:  printf("\r  Anomalía general: ¿densidad incorrecta?.");
  680.                   break;
  681.         }
  682.       }
  683.     else {
  684.       switch (codigo) {
  685.         case 1:   printf("\r  Format aborted by user.");
  686.                   break;
  687.         case 2:   printf("\r  Selected density is incorrect.");
  688.                   break;
  689.         case 3:   printf("\r  Diskette is write-protected.");
  690.                   break;
  691.         case 6:
  692.         case 128: printf("\r  Drive not ready (door open?).");
  693.                   break;
  694.         default:  printf("\r  General failure: incorrect density?.");
  695.                   break;
  696.         }
  697.       }
  698.   printf("                                  \n");
  699. }
  700.  
  701.  
  702. int MarcaFat (unidad, modosuave, sector0, cil, cab, fat, bytes_mal)
  703. struct   boot *sector0;
  704. int      unidad, modosuave, cil, cab;
  705. unsigned char far *fat;
  706. long     *bytes_mal;
  707. {
  708.   unsigned malclus, i, ini, tamsys;
  709.  
  710.   tamsys = sector0->NumFats*sector0->SectFat+(sector0->FichRaiz>>4)+1;
  711.  
  712.   for (i=1; i<=sector0->SectPista; i++) {
  713.     ini=(cil*sector0->Caras+cab)*sector0->SectPista+i-1;
  714.     if (modosuave)
  715.         malclus=biosdsk (2, unidad, cab, cil, i, 1, buffer);
  716.       else
  717.         malclus=1;  /* por defecto marcar la pista entera */
  718.     if (malclus) {
  719.       if (ini<tamsys) break;  /* error en áreas del sistema */
  720.       *bytes_mal+=sector0->SectCluster*512L;
  721.       ini-=tamsys; ini=ini/sector0->SectCluster+2;
  722.       if (ini % 2) { /* posición impar */
  723.           fat [ini*3/2] = fat [ini*3/2] & 0x0F | 0x70;
  724.           fat [ini*3/2+1] = 0xFF;
  725.           }
  726.         else {       /* posición par */
  727.           fat [ini*3/2] = 0xF7;
  728.           fat [ini*3/2+1] = fat [ini*3/2+1] & 0xF0 | 0x0F;
  729.           }
  730.       ini=0x7FFF;
  731.       }
  732.     }
  733.   return (ini>=tamsys);
  734. }
  735.  
  736.  
  737. int TipoDrive (int unidad)
  738. {
  739.   union REGS r;
  740.  
  741.   r.h.ah=8; r.h.dl=unidad;
  742.   int86 (0x13, &r, &r);
  743.  
  744.   return ((unsigned char) r.h.bl);
  745. }
  746.  
  747.  
  748. InicializaDisco (unidad, sector0, fat1)
  749. int      unidad;
  750. struct   boot *sector0;
  751. unsigned char far *fat1;
  752. {
  753.   unsigned char far *p;
  754.   int      sectpista0=sector0->Salto[sector0->OffsetPista0];
  755.  
  756.   p=buffer;
  757.     memcpy (p, sector0, 512);                /* BOOT físico */
  758.   p+=512;
  759.     memcpy (p, fat1, sector0->SectFat*512);  /* FAT1 (la 2 emulada) */
  760.   p+=sector0->SectFat*512;
  761.     memcpy (p, sector0, 512);                /* BOOT virtual */
  762.   p+=512;
  763.     memcpy (p, &Boot2mCode, Boot2mLong);     /* código SuperBOOT */
  764.  
  765.   biosdsk (0, unidad);
  766.   return (biosdsk(3, unidad, 0x80, 0, 1, sectpista0, buffer));
  767. }
  768.  
  769.  
  770. void SonidoSube()
  771. {
  772.   int frec=50;
  773.  
  774.   SonidoOn();
  775.   while (frec<5000) {
  776.     Sonido (frec); PicoRetardo(); Sonido (frec+1000); PicoRetardo();
  777.     frec+=10;
  778.   }
  779.   SonidoOff();
  780. }
  781.  
  782.  
  783. void SonidoBaja()
  784. {
  785.   int frec=6000;
  786.  
  787.   SonidoOn();
  788.   while (frec>1050) {
  789.     Sonido (frec); PicoRetardo(); Sonido (frec-1000); PicoRetardo();
  790.     frec-=10;
  791.   }
  792.   SonidoOff();
  793. }
  794.  
  795.  
  796. void SonidoError()
  797. {
  798.   int frec1=50, frec2=6000;
  799.  
  800.   SonidoOn();
  801.   while (frec1<5000) {
  802.     Sonido (frec1); PicoRetardo(); Sonido (frec1+1000); PicoRetardo();
  803.     Sonido (frec2); PicoRetardo(); Sonido (frec2-1000); PicoRetardo();
  804.     frec1+=10; frec2-=10;
  805.   }
  806.   SonidoOff();
  807. }
  808.  
  809.  
  810. void SonidoOn()
  811. {
  812.   disable(); outportb (0x61, inportb (0x61) | 3); enable();
  813.   outportb (0x43, 182);  /* preparar canal 2 */
  814. }
  815.  
  816.  
  817. void SonidoOff()
  818. {
  819.   disable(); outportb (0x61, inportb (0x61) & 0xFC); enable();
  820. }
  821.  
  822.  
  823. void Sonido (int frecuencia)
  824. {
  825.   unsigned periodo;
  826.  
  827.   periodo=1193180L/frecuencia;
  828.   outportb (0x42, periodo & 0xFF);  outportb (0x42, periodo >> 8);
  829. }
  830.  
  831.  
  832. int EsperarCambioDisco (int unidad)
  833. {
  834.   int    i;
  835.   long   hora;
  836.  
  837.   while (bioskey(1)) (void) bioskey(0);   /* limpiar buffer teclado */
  838.  
  839.   pokeb(0x40,0x3F, peekb(0x40, 0x3F) & 0xF0); /* "motores apagados" */
  840.  
  841.   do {                           /* esperar que retiren el disquete */
  842.     hora=*cbios+5;
  843.     while (*cbios<hora);
  844.     outportb (FD_DOR, (1<<(unidad+4)) | unidad | 4+8);  /* encender */
  845.     i=inportb (FD_DIR);                     /* leer línea de cambio */
  846.     outportb (FD_DOR, unidad | 4+8);                /* apagar motor */
  847.     i = (i >> 7) | bioskey(1);
  848.   } while (!i);
  849.                              /* intento de bajar la línea de cambio */
  850.   while (i && !bioskey(1)) {                  /* y parpadeo del LED */
  851.     hora=*cbios+7;
  852.     pokeb (0x40, 0x40, 0xFF);       /* para BIOS pelmas no estándar */
  853.     outportb (FD_DOR,(1<<(unidad+4)) | unidad | 4+8);   /* encender */
  854.     posicionar (unidad, 1);
  855.     while ((*cbios<hora) && !bioskey(1));
  856.     hora+=14;
  857.     posicionar (unidad, 0);
  858.     i = inportb (FD_DIR) >> 7;              /* leer línea de cambio */
  859.     outportb (FD_DOR, unidad | 4+8);                /* apagar motor */
  860.     while ((*cbios<hora) && !bioskey(1));
  861.     }
  862.   return (bioskey(1)?(bioskey(0) & 0xFF)!=0x1B:1);
  863. }
  864.  
  865.  
  866. void posicionar (int unidad, int cilindro)         /* mover cabezal */
  867. {
  868.   outfdc (0xF);          /* comando 'Seek' */
  869.   outfdc (unidad);       /* byte 1 de dicho comando */
  870.   outfdc (cilindro);
  871.  
  872.   EsperarInt();          /* esperar interrupción */
  873.  
  874.   outfdc (8);            /* comando 'leer estado de interrupciones' */
  875.  
  876.   (void) infdc();  (void) infdc();
  877. }
  878.  
  879.  
  880. void outfdc (unsigned char dato)     /* enviar byte al FDC */
  881. {                                    /* no esperando más de 440 ms */
  882.   int  i=0, rd;
  883.   long t;
  884.  
  885.   do {
  886.     i++; t=*cbios;
  887.     while ((t==*cbios) && ((rd=inportb(FD_STATUS)>>7)==0));
  888.   } while ((i<8) && !rd);
  889.  
  890.   if (rd) outportb (FD_DATA, dato);
  891. }
  892.  
  893.  
  894. int infdc (void)     /* leer byte del FDC */
  895. {                    /* no esperando más de 440 ms */
  896.   int  i=0, rd;
  897.   long t;
  898.  
  899.   do {
  900.     i++; t=*cbios;
  901.     while ((t==*cbios) && ((rd=inportb(FD_STATUS)>>7)==0));
  902.   } while ((i<8) && !rd);
  903.  
  904.   if (rd) return (inportb (FD_DATA)); else return (-1);  /* fallo */
  905. }
  906.  
  907.  
  908. void EsperarInt (void)     /* Esperar interrupción no más de 2 seg. */
  909. {
  910.   int  i=0;
  911.   long t;
  912.  
  913.   do {
  914.     i++; t=*cbios;
  915.     while ((t==*cbios) && !(*irq6 & 0x80));
  916.   } while ((i<37) && !(*irq6 & 0x80));
  917.  
  918.   *irq6=*irq6 & 0x7F;
  919. }
  920.  
  921.  
  922. int HablaSp()        /* devolver 1 si mensajes en castellano */
  923. {
  924.   union REGS r; struct SREGS s;
  925.   char info[64];
  926.   int i, idioma, spl[]={54, 591, 57, 506, 56, 593, 503, 34, 63, 502,
  927.              504, 212, 52, 505, 507, 595, 51, 80, 508, 598, 58, 3, 0};
  928.  
  929.   idioma=0;          /* supuesto el inglés */
  930.  
  931.   if (_osmajor>=3) {
  932.     r.x.ax=0x3800; s.ds=FP_SEG(info); r.x.dx=FP_OFF(info);
  933.     intdosx (&r, &r, &s);
  934.     i=0; while (spl[i++]) if (spl[i-1]==r.x.bx) idioma=1;
  935.     }
  936.  
  937.   return (idioma);
  938. }
  939.